package com.xjwn.datasync;

import com.xjwn.datasync.util.SpringContextUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;
import java.util.Objects;

//Runnable接口实现类
//被定时任务线程池调用，用来执行指定bean里面的方法。
@Slf4j
public class SchedulingRunnable implements Runnable {

   private String beanName;
 
   private String methodName;
 
   private String params;

   private String sdbUrl;
   private String tdbUrl;
   private String remark;
   private  String beginTime;
   private String endTime;
   private String procName;
   private String pkName;
   private String yydm;
   private String yymc;
   //构造函数
   public SchedulingRunnable(String beanName, String methodName,String params) {
      this(beanName, methodName, params,null,null,null,null,null,null,null,null,null);
   }

   //构造函数
   public SchedulingRunnable(String beanName, String methodName, String params,String sdbUrl,String tdbUrl,String remark,String beginTime,String endTime,String procName,String pkName,String yydm,String yymc) {
      this.beanName = beanName;
      this.methodName = methodName;
      this.params = params;
      this.sdbUrl=sdbUrl;
      this.tdbUrl=tdbUrl;
      this.remark=remark;
      this.beginTime=beginTime;
      this.endTime=endTime;
      this.procName=procName;
      this.pkName=pkName;
      this.yydm=yydm;
      this.yymc=yymc;
   }
 
   @Override
   public void run() {
      log.info("定时任务开始执行 - bean：{}，方法：{}，参数：{}，源数据源：{}，目标数据源：{}", remark, methodName, remark,sdbUrl,tdbUrl);
      //计算开始时间
      long startTime = System.currentTimeMillis();
 
      try {
         //获取bean对象
         Object target = SpringContextUtils.getBean(beanName);
 
         Method method = null;
         try {
            if (StringUtils.hasLength(params)) {
               //利用反射获取bean对象中名为methodName的方法，且接收String类型的参数
               System.out.println("1111111111111");
               method = target.getClass().getDeclaredMethod(methodName, String.class,String.class,String.class,String.class,String.class,String.class,String.class,String.class,String.class,String.class,String.class);
               System.out.println("333333333333");
            } else {
               //利用反射获取bean对象中名为methodName的方法，省略String类型的参数
               System.out.println("2222222222222");
               method = target.getClass().getDeclaredMethod(methodName);
            }
         }catch (Exception ex) {
            log.error(String.format("定时任务执行异常11111 - bean：%s，方法：%s，参数：%s ,目标 %s", beanName, methodName, params,remark), ex);
         }

         //将传入的 Method 对象设置为可访问状态。
         //如果方法是私有的或受保护的，这行代码会绕过 Java 的访问控制检查，使得后续可以通过反射调用该方法。
         ReflectionUtils.makeAccessible(method);
         try {
            if (StringUtils.hasLength(params)) {
               //通过反射机制调用目标对象的方法,并参入String的参数
               method.invoke(target, params, sdbUrl,tdbUrl,remark,beginTime,endTime,procName,pkName,yydm,yymc,"false");
            } else {
               //通过反射机制调用目标对象的方法
               method.invoke(target);
            }
         }catch (Exception ex) {
            log.error(String.format("定时任务执行异常2222222 - bean：%s，方法：%s，参数：%s ", beanName, methodName, remark), ex);
         }

      } catch (Exception ex) {
         log.error(String.format("定时任务执行异常 - bean：%s，方法：%s，参数：%s ", beanName, methodName, remark), ex);
      }

      //计算结束时间
      long times = System.currentTimeMillis() - startTime;
      log.info("定时任务执行结束 - bean：{}，方法：{}，参数：{}，耗时：{} 毫秒", beanName, methodName, remark, times);
   }


   //在 Java 中，当对象被存储在集合（如 HashMap, HashSet）中时，这两个方法非常重要。
   //equals: 用于判断两个对象是否相等。
   //hashCode: 用于快速查找对象的位置。

   @Override
   public boolean equals(Object o) {
      //如果当前对象和传入的对象是同一个实例（即引用相同），则返回 true。
      if (this == o) return true;
      //如果传入的对象为 null 或者两个对象的类类型不同，则返回 false。
      if (o == null || getClass() != o.getClass()) return false;

      SchedulingRunnable that = (SchedulingRunnable) o;
      if (params == null) {
         return beanName.equals(that.beanName) &&
               methodName.equals(that.methodName) &&
               that.params == null;
      }
 
      return beanName.equals(that.beanName) &&
            methodName.equals(that.methodName) &&
            params.equals(that.params);
   }
 
   @Override
   public int hashCode() {
      if (params == null) {
         return Objects.hash(beanName, methodName);
      }
      return Objects.hash(beanName, methodName, params);
   }


}  